import { ElLoading, ElMessage } from 'element-plus';
import * as XLSX from 'xlsx';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';

// 导出格式类型
export type ExportFormat = 'xlsx' | 'csv' | 'pdf';

// 列配置项
export interface ExportColumn<T = any> {
  key: keyof T;
  title: string;
  formatter?: (value: any, row: T) => string;
}

// 导出配置项
export interface ExportOptions<T = any> {
  data: T[];
  fileName: string;
  format: ExportFormat;
  columns: ExportColumn<T>[];
  sheetName?: string;
  domSelector?: string;
}

/**
 * 通用文件导出工具
 */
export const exportFile = async <T = any>(options: ExportOptions<T>) => {
  const { data, fileName, format, columns, sheetName = 'Sheet1', domSelector } = options;
  const loading = ElLoading.service({
    lock: true,
    text: `正在导出 ${format.toUpperCase()} 文件...`,
    background: 'rgba(0, 0, 0, 0.7)',
  });

  try {
    switch (format) {
      case 'xlsx':
      case 'csv':
        exportExcelOrCsv({ data, fileName, format, columns, sheetName });
        break;
      case 'pdf':
        await exportPdf({ data, fileName, columns, domSelector });
        break;
      default:
        throw new Error(`不支持的导出格式：${format}`);
    }
    ElMessage.success(`${format.toUpperCase()} 文件导出成功！`);
  } catch (error) {
    console.error('导出失败：', error);
    ElMessage.error(`导出失败：${(error as Error).message || '未知错误'}`);
  } finally {
    loading.close();
  }
};

/**
 * 导出 Excel/CSV
 */
const exportExcelOrCsv = <T = any>({
  data,
  fileName,
  format,
  columns,
  sheetName,
}: Omit<ExportOptions<T>, 'domSelector'>) => {
  const formattedData = data.map((row) => {
    const formattedRow: Record<string, string> = {};
    columns.forEach(({ key, title, formatter }) => {
      const value = row[key];
      formattedRow[title] = formatter ? formatter(value, row) : (value ?? '').toString();
    });
    return formattedRow;
  });

  const worksheet = XLSX.utils.json_to_sheet(formattedData);
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
  XLSX.writeFile(workbook, `${fileName}.${format}`, { bookType: format as XLSX.BookType });
};

/**
 * 导出 PDF
 */
const exportPdf = async <T = any>({
  data,
  fileName,
  columns,
  domSelector,
}: Pick<ExportOptions<T>, 'data' | 'fileName' | 'columns' | 'domSelector'>) => {
  const doc = new jsPDF('l', 'mm', 'a4');

  if (domSelector) {
    const dom = document.querySelector(domSelector);
    if (!dom) throw new Error(`未找到选择器为 ${domSelector} 的元素`);

    const canvas = await (html2canvas as any)(dom as HTMLElement, {
      scale: 2,
      useCORS: true,
    });
    const imgData = canvas.toDataURL('image/png');
    const imgWidth = 280;
    const imgHeight = (canvas.height * imgWidth) / canvas.width;
    doc.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight);
  } else {
    if (data.length === 0) throw new Error('无数据可导出');

    const columnWidth = 270 / columns.length;
    const startY = 20;
    let currentY = startY;

    // 绘制表头
    columns.forEach((col, index) => {
      doc.text(col.title, 10 + index * columnWidth, currentY, { align: 'center' });
    });
    currentY += 10;
    doc.line(10, currentY - 5, 280, currentY - 5);

    // 绘制数据
    data.forEach((row) => {
      columns.forEach((col, index) => {
        const value = col.formatter ? col.formatter(row[col.key], row) : (row[col.key] ?? '').toString();
        doc.text(value, 10 + index * columnWidth, currentY, { align: 'center', maxWidth: columnWidth - 10 });
      });
      currentY += 10;

      // 分页
      if (currentY > 280) {
        doc.addPage();
        currentY = startY;
      }
    });
  }

  doc.save(`${fileName}.pdf`);
};

// 格式化工具
export const ExportFormatters = {
  date: (value: string | Date | '') => {
    if (!value) return '';
    const date = new Date(value);
    if (isNaN(date.getTime())) return '无效日期';
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  },
  relationship: (value: string) => {
    const map = { SELF: '本人', WIFE: '老婆', SON: '儿子', DAUGHTER: '女儿' };
    return (map as Record<string, string>)[value] || value || '未知';
  },
  boolean: (value: boolean) => value ? '是' : '否',
};